package com.ruoyi.campus.utils;

import org.apache.commons.io.FilenameUtils;
import org.apache.tika.Tika;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 文件类型判断工具类
 * 
 * @author campus-alarm
 * @date 2024-01-01
 */
public class FileTypeUtils
{
    private static final Tika tika = new Tika();

    // 图片文件扩展名
    private static final Set<String> IMAGE_EXTENSIONS = new HashSet<>(Arrays.asList(
            "jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "ico", "tiff", "tif"
    ));

    // 音频文件扩展名
    private static final Set<String> AUDIO_EXTENSIONS = new HashSet<>(Arrays.asList(
            "mp3", "wav", "flac", "aac", "ogg", "wma", "m4a", "mp2", "3gp", "amr"
    ));

    // 视频文件扩展名
    private static final Set<String> VIDEO_EXTENSIONS = new HashSet<>(Arrays.asList(
            "mp4", "avi", "mov", "wmv", "flv", "webm", "mkv", "m4v", "3gp", "rm", "rmvb"
    ));

    // 文档文件扩展名
    private static final Set<String> DOCUMENT_EXTENSIONS = new HashSet<>(Arrays.asList(
            "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "rtf", "odt", "ods", "odp"
    ));

    // 压缩文件扩展名
    private static final Set<String> ARCHIVE_EXTENSIONS = new HashSet<>(Arrays.asList(
            "zip", "rar", "7z", "tar", "gz", "bz2", "xz", "jar", "war"
    ));

    /**
     * 判断是否为图片文件
     */
    public static boolean isImage(MultipartFile file)
    {
        return isImage(file.getOriginalFilename()) || isImageByMimeType(file);
    }

    /**
     * 根据文件名判断是否为图片
     */
    public static boolean isImage(String fileName)
    {
        if (fileName == null) return false;
        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        return IMAGE_EXTENSIONS.contains(extension);
    }

    /**
     * 根据MIME类型判断是否为图片
     */
    public static boolean isImageByMimeType(MultipartFile file)
    {
        try {
            String mimeType = tika.detect(file.getInputStream());
            return mimeType != null && mimeType.startsWith("image/");
        } catch (IOException e) {
            return false;
        }
    }

    /**
     * 判断是否为音频文件
     */
    public static boolean isAudio(MultipartFile file)
    {
        return isAudio(file.getOriginalFilename()) || isAudioByMimeType(file);
    }

    /**
     * 根据文件名判断是否为音频
     */
    public static boolean isAudio(String fileName)
    {
        if (fileName == null) return false;
        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        return AUDIO_EXTENSIONS.contains(extension);
    }

    /**
     * 根据MIME类型判断是否为音频
     */
    public static boolean isAudioByMimeType(MultipartFile file)
    {
        try {
            String mimeType = tika.detect(file.getInputStream());
            return mimeType != null && mimeType.startsWith("audio/");
        } catch (IOException e) {
            return false;
        }
    }

    /**
     * 判断是否为视频文件
     */
    public static boolean isVideo(MultipartFile file)
    {
        return isVideo(file.getOriginalFilename()) || isVideoByMimeType(file);
    }

    /**
     * 根据文件名判断是否为视频
     */
    public static boolean isVideo(String fileName)
    {
        if (fileName == null) return false;
        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        return VIDEO_EXTENSIONS.contains(extension);
    }

    /**
     * 根据MIME类型判断是否为视频
     */
    public static boolean isVideoByMimeType(MultipartFile file)
    {
        try {
            String mimeType = tika.detect(file.getInputStream());
            return mimeType != null && mimeType.startsWith("video/");
        } catch (IOException e) {
            return false;
        }
    }

    /**
     * 判断是否为文档文件
     */
    public static boolean isDocument(MultipartFile file)
    {
        return isDocument(file.getOriginalFilename()) || isDocumentByMimeType(file);
    }

    /**
     * 根据文件名判断是否为文档
     */
    public static boolean isDocument(String fileName)
    {
        if (fileName == null) return false;
        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        return DOCUMENT_EXTENSIONS.contains(extension);
    }

    /**
     * 根据MIME类型判断是否为文档
     */
    public static boolean isDocumentByMimeType(MultipartFile file)
    {
        try {
            String mimeType = tika.detect(file.getInputStream());
            return mimeType != null && (
                    mimeType.startsWith("application/pdf") ||
                    mimeType.startsWith("application/msword") ||
                    mimeType.startsWith("application/vnd.ms-") ||
                    mimeType.startsWith("application/vnd.openxmlformats-") ||
                    mimeType.startsWith("text/")
            );
        } catch (IOException e) {
            return false;
        }
    }

    /**
     * 判断是否为压缩文件
     */
    public static boolean isArchive(MultipartFile file)
    {
        return isArchive(file.getOriginalFilename()) || isArchiveByMimeType(file);
    }

    /**
     * 根据文件名判断是否为压缩文件
     */
    public static boolean isArchive(String fileName)
    {
        if (fileName == null) return false;
        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        return ARCHIVE_EXTENSIONS.contains(extension);
    }

    /**
     * 根据MIME类型判断是否为压缩文件
     */
    public static boolean isArchiveByMimeType(MultipartFile file)
    {
        try {
            String mimeType = tika.detect(file.getInputStream());
            return mimeType != null && (
                    mimeType.startsWith("application/zip") ||
                    mimeType.startsWith("application/x-rar") ||
                    mimeType.startsWith("application/x-7z") ||
                    mimeType.startsWith("application/x-tar") ||
                    mimeType.startsWith("application/gzip")
            );
        } catch (IOException e) {
            return false;
        }
    }

    /**
     * 获取文件类型
     */
    public static String getFileType(MultipartFile file)
    {
        if (isImage(file)) return "image";
        if (isAudio(file)) return "audio";
        if (isVideo(file)) return "video";
        if (isDocument(file)) return "document";
        if (isArchive(file)) return "archive";
        return "other";
    }

    /**
     * 获取MIME类型
     */
    public static String getMimeType(MultipartFile file)
    {
        try {
            return tika.detect(file.getInputStream());
        } catch (IOException e) {
            return "application/octet-stream";
        }
    }

    /**
     * 验证文件类型是否被允许
     */
    public static boolean isAllowedType(MultipartFile file, String[] allowedTypes)
    {
        if (allowedTypes == null || allowedTypes.length == 0) {
            return true;
        }

        String fileType = getFileType(file);
        for (String allowedType : allowedTypes) {
            if (allowedType.equalsIgnoreCase(fileType)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 验证文件扩展名是否被允许
     */
    public static boolean isAllowedExtension(String fileName, String[] allowedExtensions)
    {
        if (fileName == null || allowedExtensions == null || allowedExtensions.length == 0) {
            return true;
        }

        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        for (String allowedExt : allowedExtensions) {
            if (allowedExt.toLowerCase().equals(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据文件大小判断是否为有效文件
     */
    public static boolean isValidFileSize(MultipartFile file, long maxSize)
    {
        return file.getSize() > 0 && file.getSize() <= maxSize;
    }

    /**
     * 检查文件是否安全（简单的恶意文件检测）
     */
    public static boolean isSafeFile(MultipartFile file)
    {
        String fileName = file.getOriginalFilename();
        if (fileName == null) return false;

        // 检查危险的扩展名
        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        String[] dangerousExtensions = {"exe", "bat", "cmd", "com", "pif", "scr", "vbs", "js", "jsp", "php", "asp"};
        
        for (String dangerous : dangerousExtensions) {
            if (dangerous.equals(extension)) {
                return false;
            }
        }

        // 检查文件头（简单检测）
        try {
            byte[] header = new byte[8];
            file.getInputStream().read(header);
            
            // 检查PE文件头
            if (header.length >= 2 && header[0] == 'M' && header[1] == 'Z') {
                return false;
            }
            
            // 检查其他可执行文件特征
            // 这里可以添加更多的文件头检测逻辑
            
        } catch (IOException e) {
            return false;
        }

        return true;
    }
} 